/** 
 * Copyright 2016 Telerik AD                                                                                                                                                                            
 *                                                                                                                                                                                                      
 * Licensed under the Apache License, Version 2.0 (the "License");                                                                                                                                      
 * you may not use this file except in compliance with the License.                                                                                                                                     
 * You may obtain a copy of the License at                                                                                                                                                              
 *                                                                                                                                                                                                      
 *     http://www.apache.org/licenses/LICENSE-2.0                                                                                                                                                       
 *                                                                                                                                                                                                      
 * Unless required by applicable law or agreed to in writing, software                                                                                                                                  
 * distributed under the License is distributed on an "AS IS" BASIS,                                                                                                                                    
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                                                                                                                             
 * See the License for the specific language governing permissions and                                                                                                                                  
 * limitations under the License.                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       

*/
(function (f, define) {
    define('kendo.autocomplete', [
        'kendo.list',
        'kendo.mobile.scroller'
    ], f);
}(function () {
    var __meta__ = {
        id: 'autocomplete',
        name: 'AutoComplete',
        category: 'web',
        description: 'The AutoComplete widget provides suggestions depending on the typed text.It also allows multiple value entries.',
        depends: ['list'],
        features: [
            {
                id: 'mobile-scroller',
                name: 'Mobile scroller',
                description: 'Support for kinetic scrolling in mobile device',
                depends: ['mobile.scroller']
            },
            {
                id: 'virtualization',
                name: 'VirtualList',
                description: 'Support for virtualization',
                depends: ['virtuallist']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, support = kendo.support, caret = kendo.caret, activeElement = kendo._activeElement, placeholderSupported = support.placeholder, ui = kendo.ui, List = ui.List, keys = kendo.keys, DataSource = kendo.data.DataSource, ARIA_DISABLED = 'aria-disabled', ARIA_READONLY = 'aria-readonly', CHANGE = 'change', DEFAULT = 'k-state-default', DISABLED = 'disabled', READONLY = 'readonly', FOCUSED = 'k-state-focused', SELECTED = 'k-state-selected', STATEDISABLED = 'k-state-disabled', HOVER = 'k-state-hover', ns = '.kendoAutoComplete', HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, proxy = $.proxy;
        function indexOfWordAtCaret(caretIdx, text, separator) {
            return separator ? text.substring(0, caretIdx).split(separator).length - 1 : 0;
        }
        function wordAtCaret(caretIdx, text, separator) {
            return text.split(separator)[indexOfWordAtCaret(caretIdx, text, separator)];
        }
        function replaceWordAtCaret(caretIdx, text, word, separator) {
            var words = text.split(separator);
            words.splice(indexOfWordAtCaret(caretIdx, text, separator), 1, word);
            if (separator && words[words.length - 1] !== '') {
                words.push('');
            }
            return words.join(separator);
        }
        var AutoComplete = List.extend({
            init: function (element, options) {
                var that = this, wrapper, disabled;
                that.ns = ns;
                options = $.isArray(options) ? { dataSource: options } : options;
                List.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                options.placeholder = options.placeholder || element.attr('placeholder');
                if (placeholderSupported) {
                    element.attr('placeholder', options.placeholder);
                }
                that._wrapper();
                that._loader();
                that._dataSource();
                that._ignoreCase();
                element[0].type = 'text';
                wrapper = that.wrapper;
                that._popup();
                element.addClass('k-input').on('keydown' + ns, proxy(that._keydown, that)).on('keypress' + ns, proxy(that._keypress, that)).on('paste' + ns, proxy(that._search, that)).on('focus' + ns, function () {
                    that._prev = that._accessor();
                    that._oldText = that._prev;
                    that._placeholder(false);
                    wrapper.addClass(FOCUSED);
                }).on('focusout' + ns, function () {
                    that._change();
                    that._placeholder();
                    wrapper.removeClass(FOCUSED);
                }).attr({
                    autocomplete: 'off',
                    role: 'textbox',
                    'aria-haspopup': true
                });
                that._enable();
                that._old = that._accessor();
                if (element[0].id) {
                    element.attr('aria-owns', that.ul[0].id);
                }
                that._aria();
                that._placeholder();
                that._initList();
                disabled = $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                }
                that.listView.bind('click', function (e) {
                    e.preventDefault();
                });
                that._resetFocusItemHandler = $.proxy(that._resetFocusItem, that);
                kendo.notify(that);
            },
            options: {
                name: 'AutoComplete',
                enabled: true,
                suggest: false,
                template: '',
                groupTemplate: '#:data#',
                fixedGroupTemplate: '#:data#',
                dataTextField: '',
                minLength: 1,
                delay: 200,
                height: 200,
                filter: 'startswith',
                ignoreCase: true,
                highlightFirst: false,
                separator: null,
                placeholder: '',
                animation: {},
                virtual: false,
                value: null
            },
            _dataSource: function () {
                var that = this;
                if (that.dataSource && that._refreshHandler) {
                    that._unbindDataSource();
                } else {
                    that._progressHandler = proxy(that._showBusy, that);
                    that._errorHandler = proxy(that._hideBusy, that);
                }
                that.dataSource = DataSource.create(that.options.dataSource).bind('progress', that._progressHandler).bind('error', that._errorHandler);
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
                this.listView.setDataSource(this.dataSource);
            },
            events: [
                'open',
                'close',
                CHANGE,
                'select',
                'filtering',
                'dataBinding',
                'dataBound'
            ],
            setOptions: function (options) {
                var listOptions = this._listOptions(options);
                List.fn.setOptions.call(this, options);
                this.listView.setOptions(listOptions);
                this._accessors();
                this._aria();
            },
            _listOptions: function (options) {
                var listOptions = List.fn._listOptions.call(this, $.extend(options, { skipUpdateOnBind: true }));
                listOptions.dataValueField = listOptions.dataTextField;
                listOptions.selectedItemChange = null;
                return listOptions;
            },
            _editable: function (options) {
                var that = this, element = that.element, wrapper = that.wrapper.off(ns), readonly = options.readonly, disable = options.disable;
                if (!readonly && !disable) {
                    wrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    element.removeAttr(DISABLED).removeAttr(READONLY).attr(ARIA_DISABLED, false).attr(ARIA_READONLY, false);
                } else {
                    wrapper.addClass(disable ? STATEDISABLED : DEFAULT).removeClass(disable ? DEFAULT : STATEDISABLED);
                    element.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable).attr(ARIA_READONLY, readonly);
                }
            },
            close: function () {
                var that = this;
                var current = that.listView.focus();
                if (current) {
                    current.removeClass(SELECTED);
                }
                that.popup.close();
            },
            destroy: function () {
                var that = this;
                that.element.off(ns);
                that.wrapper.off(ns);
                List.fn.destroy.call(that);
            },
            refresh: function () {
                this.listView.refresh();
            },
            select: function (li) {
                this._select(li);
            },
            search: function (word) {
                var that = this, options = that.options, ignoreCase = options.ignoreCase, separator = options.separator, length;
                word = word || that._accessor();
                clearTimeout(that._typingTimeout);
                if (separator) {
                    word = wordAtCaret(caret(that.element)[0], word, separator);
                }
                length = word.length;
                if (!length || length >= options.minLength) {
                    that._open = true;
                    that._mute(function () {
                        this.listView.value([]);
                    });
                    that._filterSource({
                        value: ignoreCase ? word.toLowerCase() : word,
                        operator: options.filter,
                        field: options.dataTextField,
                        ignoreCase: ignoreCase
                    });
                }
            },
            suggest: function (word) {
                var that = this, key = that._last, value = that._accessor(), element = that.element[0], caretIdx = caret(element)[0], separator = that.options.separator, words = value.split(separator), wordIndex = indexOfWordAtCaret(caretIdx, value, separator), selectionEnd = caretIdx, idx;
                if (key == keys.BACKSPACE || key == keys.DELETE) {
                    that._last = undefined;
                    return;
                }
                word = word || '';
                if (typeof word !== 'string') {
                    if (word[0]) {
                        word = that.dataSource.view()[List.inArray(word[0], that.ul[0])];
                    }
                    word = word ? that._text(word) : '';
                }
                if (caretIdx <= 0) {
                    caretIdx = value.toLowerCase().indexOf(word.toLowerCase()) + 1;
                }
                idx = value.substring(0, caretIdx).lastIndexOf(separator);
                idx = idx > -1 ? caretIdx - (idx + separator.length) : caretIdx;
                value = words[wordIndex].substring(0, idx);
                if (word) {
                    word = word.toString();
                    idx = word.toLowerCase().indexOf(value.toLowerCase());
                    if (idx > -1) {
                        word = word.substring(idx + value.length);
                        selectionEnd = caretIdx + word.length;
                        value += word;
                    }
                    if (separator && words[words.length - 1] !== '') {
                        words.push('');
                    }
                }
                words[wordIndex] = value;
                that._accessor(words.join(separator || ''));
                if (element === activeElement()) {
                    caret(element, caretIdx, selectionEnd);
                }
            },
            value: function (value) {
                if (value !== undefined) {
                    this.listView.value(value);
                    this._accessor(value);
                    this._old = this._accessor();
                    this._oldText = this._accessor();
                } else {
                    return this._accessor();
                }
            },
            _click: function (e) {
                var item = e.item;
                var element = this.element;
                e.preventDefault();
                this._active = true;
                if (this.trigger('select', { item: item })) {
                    this.close();
                    return;
                }
                this._oldText = element.val();
                this._select(item);
                this._blur();
                caret(element, element.val().length);
            },
            _resetFocusItem: function () {
                var index = this.options.highlightFirst ? 0 : -1;
                if (this.options.virtual) {
                    this.listView.scrollTo(0);
                }
                this.listView.focus(index);
            },
            _listBound: function () {
                var that = this;
                var popup = that.popup;
                var options = that.options;
                var data = that.dataSource.flatView();
                var length = data.length;
                var isActive = that.element[0] === activeElement();
                var action;
                that._angularItems('compile');
                that._resizePopup();
                popup.position();
                if (length) {
                    if (options.suggest && isActive) {
                        that.suggest(data[0]);
                    }
                }
                if (that._open) {
                    that._open = false;
                    action = length ? 'open' : 'close';
                    if (that._typingTimeout && !isActive) {
                        action = 'close';
                    }
                    if (length) {
                        that._resetFocusItem();
                        if (options.virtual) {
                            that.popup.unbind('activate', that._resetFocusItemHandler).one('activate', that._resetFocusItemHandler);
                        }
                    }
                    popup[action]();
                    that._typingTimeout = undefined;
                }
                if (that._touchScroller) {
                    that._touchScroller.reset();
                }
                that._hideBusy();
                that._makeUnselectable();
                that.trigger('dataBound');
            },
            _mute: function (callback) {
                this._muted = true;
                callback.call(this);
                this._muted = false;
            },
            _listChange: function () {
                var isActive = this._active || this.element[0] === activeElement();
                if (isActive && !this._muted) {
                    this._selectValue(this.listView.selectedDataItems()[0]);
                }
            },
            _selectValue: function (dataItem) {
                var separator = this.options.separator;
                var text = '';
                if (dataItem) {
                    text = this._text(dataItem);
                }
                if (text === null) {
                    text = '';
                }
                if (separator) {
                    text = replaceWordAtCaret(caret(this.element)[0], this._accessor(), text, separator);
                }
                this._prev = text;
                this._accessor(text);
                this._placeholder();
            },
            _change: function () {
                var that = this;
                var value = that.value();
                var trigger = value !== List.unifyType(that._old, typeof value);
                var valueUpdated = trigger && !that._typing;
                var itemSelected = that._oldText !== value;
                if (valueUpdated || itemSelected) {
                    that.element.trigger(CHANGE);
                }
                if (trigger) {
                    that._old = value;
                    that.trigger(CHANGE);
                }
                that.typing = false;
            },
            _accessor: function (value) {
                var that = this, element = that.element[0];
                if (value !== undefined) {
                    element.value = value === null ? '' : value;
                    that._placeholder();
                } else {
                    value = element.value;
                    if (element.className.indexOf('k-readonly') > -1) {
                        if (value === that.options.placeholder) {
                            return '';
                        } else {
                            return value;
                        }
                    }
                    return value;
                }
            },
            _keydown: function (e) {
                var that = this;
                var key = e.keyCode;
                var visible = that.popup.visible();
                var current = this.listView.focus();
                that._last = key;
                if (key === keys.DOWN) {
                    if (visible) {
                        this._move(current ? 'focusNext' : 'focusFirst');
                    }
                    e.preventDefault();
                } else if (key === keys.UP) {
                    if (visible) {
                        this._move(current ? 'focusPrev' : 'focusLast');
                    }
                    e.preventDefault();
                } else if (key === keys.ENTER || key === keys.TAB) {
                    if (key === keys.ENTER && visible) {
                        e.preventDefault();
                    }
                    if (visible && current) {
                        if (that.trigger('select', { item: current })) {
                            return;
                        }
                        this._select(current);
                    }
                    this._blur();
                } else if (key === keys.ESC) {
                    if (visible) {
                        e.preventDefault();
                    }
                    that.close();
                } else {
                    that._search();
                }
            },
            _keypress: function () {
                this._oldText = this.element.val();
                this._typing = true;
            },
            _move: function (action) {
                this.listView[action]();
                if (this.options.suggest) {
                    this.suggest(this.listView.focus());
                }
            },
            _hideBusy: function () {
                var that = this;
                clearTimeout(that._busy);
                that._loading.hide();
                that.element.attr('aria-busy', false);
                that._busy = null;
            },
            _showBusy: function () {
                var that = this;
                if (that._busy) {
                    return;
                }
                that._busy = setTimeout(function () {
                    that.element.attr('aria-busy', true);
                    that._loading.show();
                }, 100);
            },
            _placeholder: function (show) {
                if (placeholderSupported) {
                    return;
                }
                var that = this, element = that.element, placeholder = that.options.placeholder, value;
                if (placeholder) {
                    value = element.val();
                    if (show === undefined) {
                        show = !value;
                    }
                    if (!show) {
                        if (value !== placeholder) {
                            placeholder = value;
                        } else {
                            placeholder = '';
                        }
                    }
                    if (value === that._old && !show) {
                        return;
                    }
                    element.toggleClass('k-readonly', show).val(placeholder);
                    if (!placeholder && element[0] === document.activeElement) {
                        caret(element[0], 0, 0);
                    }
                }
            },
            _search: function () {
                var that = this;
                clearTimeout(that._typingTimeout);
                that._typingTimeout = setTimeout(function () {
                    if (that._prev !== that._accessor()) {
                        that._prev = that._accessor();
                        that.search();
                    }
                }, that.options.delay);
            },
            _select: function (candidate) {
                this._active = true;
                this.listView.select(candidate);
                this._active = false;
            },
            _loader: function () {
                this._loading = $('<span class="k-icon k-loading" style="display:none"></span>').insertAfter(this.element);
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
            },
            _wrapper: function () {
                var that = this, element = that.element, DOMelement = element[0], wrapper;
                wrapper = element.parent();
                if (!wrapper.is('span.k-widget')) {
                    wrapper = element.wrap('<span />').parent();
                }
                wrapper.attr('tabindex', -1);
                wrapper.attr('role', 'presentation');
                wrapper[0].style.cssText = DOMelement.style.cssText;
                element.css({
                    width: '100%',
                    height: DOMelement.style.height
                });
                that._focused = that.element;
                that.wrapper = wrapper.addClass('k-widget k-autocomplete k-header').addClass(DOMelement.className);
            }
        });
        ui.plugin(AutoComplete);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));